根据组合数可以得到只要一个房间里有
当
考虑一个问题,设置一个数据
我们设
再设数列
这样可以获得足够的随机性,并且根据生日悖论,只要生成
设
于是我们再设数列
再应用一次生日悖论可以得到时间复杂度为
假设两个人同时同向同地开始赛跑,A 的速度快,B 的速度慢,经过一定时间后,A 一定会追上 B,且 B 第一次被追上时 A 跑过的总距离减去 B 跑过的总距离一定是圈长的
于是我们可以写出这样的代码:
inline __int128 abs(__int128 x) { return x < 0 ? -x : x; }static unsigned long long seed;unsigned long long u64_hasher(unsigned long long x) { return x *= 0x1952BB648B74B19Eull, x ^= x >> 47, x *= 0x1952BB648B74B19Eull, x ^= x >> 47, x * 0x1952BB648B74B19Eull;}unsigned long long rng() { return seed += u64_hasher(seed); }static std::mt19937_64 rng;inline uint64_t rho(uint64_t value) { if (value % 2 == 0) return 2; if (value % 3 == 0) return 3; if (value % 5 == 0) return 5; if (value % 7 == 0) return 7; mint::set_mod(value); mint x, y; mint c; while (true) { c = rng(); y = c; x = c * c + c; while (x != y) { mint z((uint64_t)abs((__int128)y.val() - (__int128)x.val())); if (uint64_t g = std::__gcd(z.val(), value); g > 1 && g < value) return g; y = y * y + c; x = x * x + c; x = x * x + c; } }}上面的做法要调用很多次
其实这个
修改上述结论:假设两个人同时同向同地开始赛跑,A 的速度快,B 的速度慢,经过一定时间后,A 一定会追上 B,且此时 A 跑过的总距离减去 B 跑过的总距离一定是圈长的
我们每过一段时间将这些差值进行
如果某一时刻得到
更正:由拉梅定理得到
用几个小素数判一下效率会有显著提升(?)。
附带 abs(__int128)、readu128()、putu128()。这份代码中采用倍增优化,
这里有一个小技巧:只改变
inline __int128 abs(__int128 x) { return x < 0 ? -x : x; }static unsigned long long seed;unsigned long long u64_hasher(unsigned long long x) { return x *= 0x1952BB648B74B19Eull, x ^= x >> 47, x *= 0x1952BB648B74B19Eull, x ^= x >> 47, x * 0x1952BB648B74B19Eull;}unsigned long long rng() { return seed += u64_hasher(seed); }static std::mt19937_64 rng;inline __uint128_t rho(__uint128_t value) { if (value % 2 == 0) return 2; if (value % 3 == 0) return 3; if (value % 5 == 0) return 5; if (value % 7 == 0) return 7; mint::set_mod(value); mint x, y, z, c; uint64_t i, j; __uint128_t g; while (true) { y = x = rng(); z = 1; c = rng(); i = 0; j = 1; while (++i) { x = x * x + c; z *= mint((__uint128_t)abs((__int128)y.val() - (__int128)x.val())); if (x == y || !z.val()) break; if (!(i & 32767) || i == j) { g = std::__gcd(z.val(), value); if (g > 1ull) return g; if (i == j) { y = x; j <<= 1; } } } }}inline auto crack(__uint128_t value) { struct _RetType { __uint128_t base; uint64_t power; }; std::vector<_RetType> ret; if (prime(value)) { ret.push_back({value, 1ul}); return ret; } _RetType node{2, 0}; while (value % 2 == 0) ++(node.power), value >>= 1; if (node.power) ret.push_back(node); auto dfs = [&](auto self, __uint128_t v) { if (v <= 1) return; if (!prime(v)) { __uint128_t tmp = rho(v); self(self, tmp); self(self, v / tmp); } else { auto pos = std::find_if(ret.begin(), ret.end(), [=](const auto& x) { return x.base == v; }); if (pos == ret.end()) ret.push_back({v, 1ul}); else ++(pos->power); } }; dfs(dfs, value); std::sort(ret.begin(), ret.end(), [=](const auto& x, const auto& y) { return x.base < y.base; }); return ret;}inline __uint128_t readu128() { __uint128_t ret = 0; char c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) ret = ret * 10 + (c & 15), c = getchar(); return ret;}inline void putu128(__uint128_t x) { static char buf[45]; static int curpos; curpos = 0; do { buf[curpos++] = x % 10; x /= 10; } while (x); while (curpos--) putchar(buf[curpos] | 48);}